// #include "simple/support/debug.hpp"

#include "simple/compress/huffman.hpp"
#include "simple/compress/iterator.hpp" // out_bits
#include "simple/support/iterator.hpp" // offset_expander

#include <cassert>
#include <vector>
#include <string>
#include <cstdio>

using namespace simple::compress;

void Endecode(std::string text)
{
	std::vector<std::byte> encoded;
	encoded.reserve(text.size());

	auto code = huffman_code(text.begin(), text.end());

#if defined SIMPLE_SUPPORT_DEBUG_HPP
		simple::support::print('\n');
		simple::support::println("CODE: ");
		code.for_each([](auto && kv) { using std::to_string; if(bit_count(kv.second) != 0) simple::support::println(to_string((int)kv.first) + " - " + to_string(kv.second)); });
		simple::support::print('\n');
#endif

	huffman_encode(code, text.begin(), text.end(), out_bits(simple::support::offset_expander(encoded)));

#if defined SIMPLE_SUPPORT_DEBUG_HPP
	simple::support::print("INPUT SIZE: ", text.size(), '\n');
	simple::support::print("COMPRESSED SIZE: ", encoded.size(), '\n');
#endif

	std::string decoded;
	decoded.resize(text.size());
	huffman_decode(code, encoded.begin(), decoded.begin(), decoded.end());

	assert(text == decoded);
}

int main(int argc, char const* argv[])
{
	std::string text = "abcd aaaa bbbb cccc aaaa abcd aaaa aaaa aaaa aaaaa aaaa aaaaaaaaaaa aaaaaaaaaaaaa aaaaaaaaaaaaaa aaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaa";
	if(argc > 1)
	{
		auto f = std::fopen(argv[1], "rb");
		std::fseek(f,0,SEEK_END);
		text.resize(std::ftell(f));
		std::fseek(f,0,SEEK_SET);
		auto unused [[maybe_unused]] = std::fread(text.data(), text.size(), 1 ,f);
#if defined SIMPLE_SUPPORT_DEBUG_HPP
		simple::support::print("s: ", text.size(), '\n');
#endif
	}
	Endecode(std::move(text));
	return 0;
}
